//***1.实验前准备

//获取当前时间
const nowdate = new Date(),
year = nowdate.getFullYear(),
month = nowdate.getMonth() + 1,  //Date对象的getMonth方法返回的月份从0开始，因此+1
date = nowdate.getDate(),
hours = nowdate.getHours(),
minutes = nowdate.getMinutes(),
seconds = nowdate.getSeconds();

// 定义最后生成实验数据的文件名变量，使其能重命名为生成文件时的日期时间，具体到秒；月份和日期应该至少有两位数字，不足的前面补0
const file_name = year + '_' + 
                  month.toString().padStart(2, '0') + '_' + 
                  date.toString().padStart(2, '0') + '_' + 
                  hours.toString().padStart(2, '0') + 
                  minutes.toString().padStart(2, '0') + 
                  seconds.toString().padStart(2, '0')

//初始化jsPsych
let jsPsych = initJsPsych({
    // 当实验结束时执行的回调函数
    on_finish: function () {
        let csvContent = jsPsych.data.get().csv();  // 获取CSV格式的数据内容
        let utf8BOM = '\uFEFF';  // 添加UTF-8 BOM，确保Excel在打开文件时正确地识别UTF-8编码，中文字不乱吗
        let blob = new Blob([utf8BOM + csvContent], {type: 'text/csv;charset=utf-8;'});  // 创建Blob对象并保存文件
        let url = URL.createObjectURL(blob);  // 使用URL.createObjectURL生成URL并创建下载链接

        // 创建下载链接并模拟点击以下载文件
        let link = document.createElement('a');
        link.setAttribute('href', url);
        link.setAttribute('download', `${file_name}.csv`);  //定义实验数据文件命名
        document.body.appendChild(link);
        link.click();

        // 清理创建的链接对象
        document.body.removeChild(link);

        //呈现结束指导语
        document.getElementById('jspsych-content').innerHTML +=
        '<h2>本次实验到此结束，感谢您的参与！</h2>'
    }
});



let timeline = [];  //定义时间线，用于存放实验的各个阶段任务



//***整个试验的指导语、进入全屏实验
let start = {   
    type: jsPsychFullscreen,  // 使用 jsPsychFullscreen 插件进入全屏模式
    fullscreen_mode: true,
    message: `
    <div class="container">
        <div class="item"> <strong>欢迎参加实验！请仔细阅读以下内容：</strong></div>
        <div class="item"> 1. 本次实验包含3个部分：①信息收集；②按键反应；③量表测评</div>
        <div class="item"> 2. 请关掉电脑上其他运行的程序，并在安静的环境下进行实验</div>
        <div class="item"> 3. 为保证最佳效果，实验开始后将进入全屏模式，请保持全屏完成实验</div>
        <div class="item"> 4. 如果您已清楚上述要求，并同意参与实验，请点击下方按钮开始</div>
    </div>
        <br><p style="font-size: 15px; color: red;">注意：在实验中如有任何问题，请及时联系主试 </p><br>  
        `,
    button_label: '<p><strong>开始实验</strong><p>',
    delay_after: 1000  // 在显示完全屏信息后延迟1秒继续下一步
}

timeline.push(start)



//***被试信息收集
let sub_info = {
    type: jsPsychSurvey,  // 使用 jsPsychSurvey 插件进行调查问卷
    survey_json: {
    showQuestionNumbers: true,  // 显示问题编号
    title:'被试信息收集',  // 调查问卷标题
    completeText: '完成',
    elements:
      [
        {
            type: 'text',
            title: "您的编号", 
            name: 'id', 
            isRequired: true,
            maskType: "pattern",
            maskSettings: {
              pattern: "9999"  // 设定4位数编号
            }
          },
          {
            type: 'text',
            title: '您的年龄', 
            name: 'age', 
            isRequired: true,
            inputType: 'number',
            min: 0,
            max: 100,
            defaultValue: 0
          },
          {
            type: 'text',
            title: "您的学校", 
            name: 'chool', 
            isRequired: true,
          },
          {
            type: 'text',
            title: "您的专业", 
            name: 'major', 
            isRequired: true,
          },
          {
            type: 'radiogroup',
            title: "您的性别", 
            name: 'gender', 
            isRequired: true,
            choices: ['男', '女'],
          },
          {
            type: 'radiogroup',
            title: "您的利手", 
            name: 'handedness', 
            isRequired: true,
            choices: ['左', '右'],
          },
    ],
  },
};
timeline.push(sub_info);



//***按键实验的指导语
let instruction1 = {
    type: jsPsychHtmlKeyboardResponse,  // 使用 jsPsychHtmlKeyboardResponse 插件进行 HTML 键盘响应
    stimulus: `
    <div class="container" style="align-items: center"><strong>按键实验</strong></div>
    <p>接下来，您将完成一个按键实验。</p>
    <p>在实验中，您将看到一系列旋转的字母 “R” 。</p>
    <p>您需要判断字母 “R” 是 <strong>“正R”</strong> 还是 <strong>“反R”</strong> 。</p>
    <table style="display: flex;justify-content: center;">
        <tr>
            <td style="border: 1px solid #333;border-radius: 10px;font-weight: bold; padding: 6px 20px;transform: scaleX(1);">R</td>
            <td style="width: 1.5em;"></td>
            <td>正R请按【F】键</td>
        </tr>
        <tr>
            <td style="border: 1px solid #333;border-radius: 10px;font-weight: bold; padding: 6px 20px;transform: scaleX(-1);">R</td>
            <td style="width: 1.5em;"></td>
            <td>反R请按【J】键</td>
        </tr>
    </table>
    <p>请尽量快速且准确地判字母的方向</p>
    <p>按任意键开始练习</p>
  `,
  post_trial_gap: 1000  // 延迟1秒继续下一步
};
timeline.push(instruction1);



//***按键实验的练习阶段（练习通过才可进入正式试验）
let fail;  // 声明一个变量 fail，用于记录是否有错误反应
let practice ={
    type: jsPsychHtmlKeyboardResponse,  // 使用 jsPsychHtmlKeyboardResponse 插件进行 HTML 键盘响应
    timeline: [
        {stimulus:'<p style="font-size:40px;">+</P>',
            choices: 'NO_KEYS',
            trial_duration: 250},
        {stimulus: '<div style="transform: scaleX(-1) rotate(240deg); font-size: 80px;">R</div>',
            choices:['f','j'], 
            on_finish: function(data){
                fail=(data.response=='f');  // 当响应为 'f' 时，记录为错误反应
        },
    },
        {
            timeline: [{stimulus:'<p style="color:red">反应错误，请按空格键重新练习<p>', choices:[' ']}],
            conditional_function: function(){
                return fail;  // 如果之前的试次有错误反应，则显示重新练习的提示
            },
        },
    ],
    loop_function: function(){
        return fail;  // 如果之前的试次有错误反应，则重复练习当前实验
    }
};
timeline.push(practice);
    


let message = {
    type: jsPsychHtmlKeyboardResponse,  // 使用 jsPsychHtmlKeyboardResponse 插件进行 HTML 键盘响应
    stimulus: '<p>反应正确，请按任意键进入正式实验</p>',
    post_trial_gap: 1000  // 在显示提示信息后延迟1秒继续下一步
};
timeline.push(message);



//***按键实验的正式阶段
let stimulus_R = [  // 定义一个数组，包含要呈现的每个字母 "R" 的属性
    {flip: 1, rotate: 0, correct_response: 'f'},    // 正向旋转0度，正确反应是按 'f'
    {flip: 1, rotate: 60, correct_response: 'f'},   // 正向旋转60度，正确反应是按 'f'
    {flip: 1, rotate: 120, correct_response: 'f'},  // 正向旋转120度，正确反应是按 'f'
    {flip: 1, rotate: 180, correct_response: 'f'},  // 正向旋转180度，正确反应是按 'f'
    {flip: 1, rotate: 240, correct_response: 'f'},  // 正向旋转240度，正确反应是按 'f'
    {flip: 1, rotate: 300, correct_response: 'f'},  // 正向旋转300度，正确反应是按 'f'
    {flip: -1, rotate: 0, correct_response: 'j'},   // 反向旋转0度，正确反应是按 'j'
    {flip: -1, rotate: 60, correct_response: 'j'},  // 反向旋转60度，正确反应是按 'j'
    {flip: -1, rotate: 120, correct_response: 'j'}, // 反向旋转120度，正确反应是按 'j'
    {flip: -1, rotate: 180, correct_response: 'j'}, // 反向旋转180度，正确反应是按 'j'
    {flip: -1, rotate: 240, correct_response: 'j'}, // 反向旋转240度，正确反应是按 'j'
    {flip: -1, rotate: 300, correct_response: 'j'}  // 反向旋转300度，正确反应是按 'j'
];

let fixation = {
    type: jsPsychHtmlKeyboardResponse,  // 使用 jsPsychHtmlKeyboardResponse 插件进行 HTML 键盘响应
    stimulus: '<p style="font-size: 40px;">+</p>',
    choices: [],
    trial_duration: 250 // 呈现250ms
};

let trials = {
    type: jsPsychHtmlKeyboardResponse,  // 使用 jsPsychHtmlKeyboardResponse 插件进行 HTML 键盘响应
    stimulus: function() {  // 使用函数动态生成呈现的 "R" 字母
        return `<div style="transform: scaleX(${jsPsych.timelineVariable('flip')}) rotate(${jsPsych.timelineVariable('rotate')}deg); font-size: 80px;">R</div>`;
    },
    choices: ['f', 'j'],
    trial_duration: 2000,  // 每个试次呈现字母 "R" 2000毫秒
    data: {  // 记录试次的数据，包括旋转方向、正确反应
        flip: jsPsych.timelineVariable('flip'),
        rotate: jsPsych.timelineVariable('rotate'),
        correct_response: jsPsych.timelineVariable('correct_response')
    },
};

let trialLoop = {
    timeline: [fixation, trials],  // 每个试次包括一个加号呈现和一个字母 "R" 呈现
    timeline_variables: stimulus_R,  // 使用定义好的 stimulus_R 数组作为时间轴变量，即不同的旋转和翻转属性
    randomize_order: true,  // 随机顺序呈现试次
    repetitions: 10,  // 每种刺激重复10次，一共120个试次
};
timeline.push(trialLoop);



//***结束按键实验，进入量表测评的指导语
let instruction2 = {
    type: jsPsychHtmlKeyboardResponse,  // 使用 jsPsychHtmlKeyboardResponse 插件进行 HTML 键盘响应
    stimulus: `
    <h2>您已完成按键实验</h2>
    <br>
    <p>接下来，您将完成一个压力量表测评</p>
    <p>答案无对错之分，请按照实际情况认真作答</p>
    <p>按任意键开始测评</p>
  `,
  post_trial_gap: 1000  // 在显示指导语后延迟1秒继续下一步
};
timeline.push(instruction2);



//***压力测评阶段（量表为李虹和梅锦荣(2002)编制的大学生压力量表，共30个题，包含学习烦扰、个人烦扰和消极生活事件三个分量表）
let sharedLabels = [
    "<br>0<br><br>没有压力", 
    "<br>1<br><br>轻度压力", 
    "<br>2<br><br>中度压力", 
    "<br>3<br><br>严重压力"
  ];  // 定义共享的选项标签，表示不同压力级别和对应描述

let stress_survey = {
    type: jsPsychSurveyLikert,  // Likert量表类型的问卷
    button_label: '继续',
    scale_width: 400,  // 每个问题的量表宽度
    questions: [
        {prompt: "1. 渴望真（爱）情却得不到", required: true, labels: sharedLabels },
        {prompt: "2. 青春期成长", required: true, labels: sharedLabels },
        {prompt: "3. 同学关系紧张", required: true, labels: sharedLabels },
        {prompt: "4. 外形不佳", required: true, labels: sharedLabels },
        {prompt: "5. 身体不好", required: true, labels: sharedLabels },
        {prompt: "6. 同学间互相攀比", required: true, labels: sharedLabels },
        {prompt: "7. 居住条件差", required: true, labels: sharedLabels },
        {prompt: "8. 遭受冷遇", required: true, labels: sharedLabels },
        {prompt: "9. 社会上的各种诱惑", required: true, labels: sharedLabels },
        {prompt: "10. 晚上宿舍太吵", required: true, labels: sharedLabels },
        {prompt: "11. 没有人追或找不到男/女朋友", required: true, labels: sharedLabels },
        {prompt: "12. 没有人说知心话", required: true, labels: sharedLabels },
        {prompt: "13. 没有学到多少真本领", required: true, labels: sharedLabels },
        {prompt: "14. 独立生活能力差", required: true, labels: sharedLabels },
        {prompt: "15. 各种应酬有困难", required: true, labels: sharedLabels },
        {prompt: "16. 家庭经济条件差", required: true, labels: sharedLabels },
        {prompt: "17. 对有些科目怎么努力成绩也不好", required: true, labels: sharedLabels },
        {prompt: "18. 学习成绩总体不理想", required: true, labels: sharedLabels },
        {prompt: "19. 讨论问题时常反应不过来", required: true, labels: sharedLabels },
        {prompt: "20. 考试压力", required: true, labels: sharedLabels },
        {prompt: "21. 同学间的竞争", required: true, labels: sharedLabels },
        {prompt: "22. 学习效率低", required: true, labels: sharedLabels },
        {prompt: "23. 每学期末考试成绩排名", required: true, labels: sharedLabels },
        {prompt: "24. 完成课业有困难", required: true, labels: sharedLabels },
        {prompt: "25. 有些课程作业太多", required: true, labels: sharedLabels },
        {prompt: "26. 各种测验繁多", required: true, labels: sharedLabels },
        {prompt: "27. 累计两门以上功课考试不及格", required: true, labels: sharedLabels },
        {prompt: "28. 一门功课考试不及格", required: true, labels: sharedLabels },
        {prompt: "29. 当众出丑", required: true, labels: sharedLabels },
        {prompt: "30. 被人当众指责", required: true, labels: sharedLabels },
    ]
  };
timeline.push(stress_survey);



//***退出全屏，结束实验
let quitFullscreenMode = {  // 定义退出全屏模式的对象，使用jsPsychFullscreen类型
    type: jsPsychFullscreen,
    fullscreen_mode: false,  // 设置退出全屏模式
};
timeline.push(quitFullscreenMode)



//前面的代码已经将所有要运行的试次添加到一个数组（即时间线）中，现在传给.run()依次运行
jsPsych.run(timeline);